// tests/setup-test-env.js - 快速设置测试环境脚本
import fs from 'fs';
import path from 'path';
import { execSync } from 'child_process';

class TestEnvironmentSetup {
  constructor() {
    this.projectRoot = process.cwd();
    this.testsDir = path.join(this.projectRoot, 'tests');
    this.reportsDir = path.join(this.projectRoot, 'test-reports');
    this.coverageDir = path.join(this.projectRoot, 'coverage');
  }

  async setupEnvironment() {
    console.log('🚀 开始设置API功能测试环境...\n');
    
    try {
      this.checkProjectStructure();
      this.createDirectories();
      this.checkDependencies();
      this.createConfigFiles();
      this.updatePackageJson();
      this.createGitIgnore();
      
      console.log('\n✅ 测试环境设置完成!');
      console.log('\n📋 下一步操作:');
      console.log('1. 运行测试: npm test');
      console.log('2. 生成报告: npm run test:report');
      console.log('3. 查看报告: open test-reports/api-test-report.html');
      
    } catch (error) {
      console.error('\n❌ 设置过程中出现错误:', error.message);
      process.exit(1);
    }
  }

  checkProjectStructure() {
    console.log('📁 检查项目结构...');
    
    const requiredFiles = ['package.json', 'src'];
    const missingFiles = requiredFiles.filter(file => 
      !fs.existsSync(path.join(this.projectRoot, file))
    );
    
    if (missingFiles.length > 0) {
      throw new Error(`缺少必要的项目文件: ${missingFiles.join(', ')}`);
    }
    
    console.log('✅ 项目结构检查通过');
  }

  createDirectories() {
    console.log('📂 创建测试目录...');
    
    const directories = [
      this.testsDir,
      this.reportsDir,
      this.coverageDir,
      path.join(this.projectRoot, 'mongodb-binaries'),
    ];
    
    directories.forEach(dir => {
      if (!fs.existsSync(dir)) {
        fs.mkdirSync(dir, { recursive: true });
        console.log(`  ✅ 创建目录: ${path.relative(this.projectRoot, dir)}`);
      } else {
        console.log(`  ✅ 目录已存在: ${path.relative(this.projectRoot, dir)}`);
      }
    });
  }

  checkDependencies() {
    console.log('📦 检查测试依赖...');
    
    const packageJsonPath = path.join(this.projectRoot, 'package.json');
    const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
    
    const requiredDeps = {
      'jest': '^29.0.0',
      'supertest': '^6.3.0',
      'mongodb-memory-server': '^9.0.0',
      'babel-jest': '^29.0.0',
      '@babel/preset-env': '^7.22.0',
    };
    
    const devDeps = packageJson.devDependencies || {};
    const missingDeps = Object.keys(requiredDeps).filter(dep => !devDeps[dep]);
    
    if (missingDeps.length > 0) {
      console.log('⚠️  缺少测试依赖，正在安装...');
      console.log(`依赖列表: ${missingDeps.join(', ')}`);
      
      try {
        const installCmd = `npm install --save-dev ${missingDeps.map(dep => `${dep}@${requiredDeps[dep]}`).join(' ')}`;
        execSync(installCmd, { stdio: 'inherit' });
        console.log('✅ 依赖安装完成');
      } catch (error) {
        throw new Error(`依赖安装失败: ${error.message}`);
      }
    } else {
      console.log('✅ 所有依赖已安装');
    }
  }

  createConfigFiles() {
    console.log('⚙️  创建配置文件...');
    
    // 创建 .env.test
    this.createEnvTestFile();
    
    // 创建 jest.config.js
    this.createJestConfig();
    
    console.log('✅ 配置文件创建完成');
  }

  createEnvTestFile() {
    const envTestPath = path.join(this.projectRoot, '.env.test');
    
    if (!fs.existsSync(envTestPath)) {
      const envContent = `NODE_ENV=test
SQ_JWT_SECRET=test-jwt-secret-key-for-testing-only
SQ_SITE_NAME=Test Tracker
SQ_BASE_URL=http://localhost:3001
SQ_API_URL=http://localhost:3001
SQ_ALLOW_REGISTER=open
SQ_DISABLE_EMAIL=true
SQ_MINIMUM_RATIO=-1
SQ_MAXIMUM_HIT_N_RUNS=-1
SQ_BP_EARNED_PER_GB=10
SQ_BP_EARNED_PER_FILLED_REQUEST=50
SQ_BP_COST_PER_INVITE=100
SQ_BP_COST_PER_GB=50
SQ_SITE_WIDE_FREELEECH=false
SQ_ALLOW_UNREGISTERED_VIEW=false
SQ_ANNOUNCE_INTERVAL=1800
SQ_MIN_ANNOUNCE_INTERVAL=900`;
      
      fs.writeFileSync(envTestPath, envContent);
      console.log('  ✅ 创建 .env.test');
    } else {
      console.log('  ✅ .env.test 已存在');
    }
  }

  createJestConfig() {
    const jestConfigPath = path.join(this.projectRoot, 'jest.config.js');
    
    if (!fs.existsSync(jestConfigPath)) {
      const jestConfig = `module.exports = {
  testEnvironment: 'node',
  setupFilesAfterEnv: ['<rootDir>/tests/setup.js'],
  testMatch: ['<rootDir>/tests/**/*.test.js'],
  collectCoverageFrom: [
    'src/**/*.{js}',
    '!src/index.js',
    '!**/node_modules/**'
  ],
  coverageDirectory: 'coverage',
  coverageReporters: ['text', 'lcov', 'html', 'json'],
  coverageThreshold: {
    global: {
      branches: 70,
      functions: 70,
      lines: 70,
      statements: 70
    }
  },
  testTimeout: 30000,
  maxWorkers: 2,
  transform: {
    '^.+\\.js$': ['babel-jest', {
      presets: [['@babel/preset-env', { targets: { node: 'current' } }]]
    }]
  },
  moduleFileExtensions: ['js', 'json'],
  testPathIgnorePatterns: ['/node_modules/', '/coverage/'],
  verbose: true
};`;
      
      fs.writeFileSync(jestConfigPath, jestConfig);
      console.log('  ✅ 创建 jest.config.js');
    } else {
      console.log('  ✅ jest.config.js 已存在');
    }
  }

  updatePackageJson() {
    console.log('📝 更新package.json脚本...');
    
    const packageJsonPath = path.join(this.projectRoot, 'package.json');
    const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
    
    const requiredScripts = {
      'test': 'NODE_ENV=test jest --detectOpenHandles',
      'test:watch': 'NODE_ENV=test jest --watch --detectOpenHandles',
      'test:coverage': 'NODE_ENV=test jest --coverage --detectOpenHandles',
      'test:verbose': 'NODE_ENV=test jest --verbose --detectOpenHandles',
      'test:silent': 'NODE_ENV=test jest --silent --detectOpenHandles',
      'test:report': 'NODE_ENV=test node tests/report-generator.js',
      'test:ci': 'NODE_ENV=test jest --coverage --ci --watchAll=false --detectOpenHandles',
    };
    
    if (!packageJson.scripts) {
      packageJson.scripts = {};
    }
    
    let scriptsAdded = 0;
    Object.entries(requiredScripts).forEach(([name, script]) => {
      if (!packageJson.scripts[name]) {
        packageJson.scripts[name] = script;
        scriptsAdded++;
        console.log(`  ✅ 添加脚本: ${name}`);
      }
    });
    
    if (scriptsAdded > 0) {
      fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
      console.log(`✅ 更新了 ${scriptsAdded} 个npm脚本`);
    } else {
      console.log('✅ npm脚本已是最新');
    }
  }

  createGitIgnore() {
    console.log('📄 更新.gitignore...');
    
    const gitignorePath = path.join(this.projectRoot, '.gitignore');
    const testIgnoreEntries = [
      '# 测试相关',
      'test-reports/',
      'coverage/',
      'mongodb-binaries/',
      '.env.test',
      '*.log',
      '.nyc_output',
    ];
    
    let gitignoreContent = '';
    if (fs.existsSync(gitignorePath)) {
      gitignoreContent = fs.readFileSync(gitignorePath, 'utf8');
    }
    
    const entriesToAdd = testIgnoreEntries.filter(entry => 
      !gitignoreContent.includes(entry)
    );
    
    if (entriesToAdd.length > 0) {
      if (gitignoreContent && !gitignoreContent.endsWith('\n')) {
        gitignoreContent += '\n';
      }
      gitignoreContent += '\n' + entriesToAdd.join('\n') + '\n';
      
      fs.writeFileSync(gitignorePath, gitignoreContent);
      console.log(`✅ 添加了 ${entriesToAdd.length} 个忽略条目到.gitignore`);
    } else {
      console.log('✅ .gitignore 已是最新');
    }
  }

  // 验证安装结果
  async verifyInstallation() {
    console.log('\n🔍 验证安装结果...');
    
    try {
      // 检查是否可以运行Jest
      execSync('npm test -- --version', { stdio: 'pipe' });
      console.log('✅ Jest 可以正常运行');
      
      // 检查必要文件是否存在
      const requiredFiles = [
        'tests/setup.js',
        'tests/api.test.js',
        'tests/report-generator.js',
        '.env.test',
        'jest.config.js',
      ];
      
      const missingFiles = requiredFiles.filter(file => 
        !fs.existsSync(path.join(this.projectRoot, file))
      );
      
      if (missingFiles.length > 0) {
        console.log('⚠️  缺少测试文件，请手动创建:');
        missingFiles.forEach(file => console.log(`  - ${file}`));
      } else {
        console.log('✅ 所有测试文件已就位');
      }
      
    } catch (error) {
      console.log('⚠️  验证过程中发现问题:', error.message);
    }
  }

  // 显示使用指南
  showUsageGuide() {
    console.log('\n📖 快速使用指南:');
    console.log('');
    console.log('1. 📥 放置测试文件到 tests/ 目录');
    console.log('   - tests/setup.js');
    console.log('   - tests/api.test.js');
    console.log('   - tests/report-generator.js');
    console.log('');
    console.log('2. 🧪 运行测试命令:');
    console.log('   npm test                 # 运行所有测试');
    console.log('   npm run test:coverage    # 生成覆盖率报告');
    console.log('   npm run test:report      # 生成详细报告');
    console.log('   npm run test:watch       # 监听模式');
    console.log('');
    console.log('3. 📊 查看测试结果:');
    console.log('   open test-reports/api-test-report.html');
    console.log('');
    console.log('4. 🔧 故障排除:');
    console.log('   npm test -- --forceExit  # 强制退出');
    console.log('   npm test -- --verbose    # 详细输出');
    console.log('');
  }
}

// 主要入口函数
async function main() {
  const setup = new TestEnvironmentSetup();
  
  try {
    await setup.setupEnvironment();
    await setup.verifyInstallation();
    setup.showUsageGuide();
  } catch (error) {
    console.error('❌ 设置失败:', error.message);
    process.exit(1);
  }
}

// 如果直接运行此脚本
if (require.main === module) {
  main().catch(console.error);
}

export default TestEnvironmentSetup;